package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoPointCut() {

    }

    /**
     * 前置通知，在通知中进行公共字段的赋值
     */
    @Before("autoPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段的赋值");

        //获取注解上的值
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取当前被拦截方法上的注解对象
        OperationType operationType = autoFill.value();//获取操作类型
        log.info("当前操作类型：{}", operationType);

        //获取当前被拦截方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];//获取当前被拦截方法的第一个参数，即实体对象
        log.info("当前被拦截方法中的实体对象：{}", entity);

        //准备公共字段数据
        Long currentId = BaseContext.getCurrentId();//获取当前操作员id
        LocalDateTime now = LocalDateTime.now();//获取当前时间
        switch (operationType) {
            case INSERT:
                try {
                    //根据当前不同的操作类型，为对应的属性进行反射赋值
                    //1、通过反射获取对象中指定属性的set方法名
                    //2、通过反射获取对象中指定属性的set方法对象Method
                    //3、通过反射调用当前对象的方法set方法实现赋值
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class).invoke(entity, now);
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class).invoke(entity, now);
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class).invoke(entity, currentId);
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class).invoke(entity, currentId);
                    //通过反射为对象属性赋值
                    log.info("为{}属性赋值", "createTime");
                    //TODO
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case UPDATE:
                try {
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class).invoke(entity, now);
                    entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class).invoke(entity, currentId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}
